<?php

namespace liketp\route;

use liketp\exception\Exception;
use liketp\Request;
use liketp\Response;

abstract class Dispatch
{
    protected $request;
    protected $rule;
    protected $dispatch;
    protected $params;
    protected $corsAllowMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD'];
    protected $corsAllowHeaders = ['X-Token', 'Auth', 'Content-Type'];

    abstract public function exec();

    public function __construct(Request $request, RuleItem $rule, $dispatch, array $params = [])
    {
        $this->request = $request;
        $this->rule = $rule;
        $this->dispatch = $dispatch;
        $this->params = $params;
    }

    public function init()
    {
        $this->request->setRouteVars($this->params);
    }

    public function run()
    {
        if ($this->rule->isAutoOptions() && $this->request->method() == 'OPTIONS') {
            $header = [
                'Access-Control-Allow-Origin' => $this->request->header('origin'),
                'Access-Control-Allow-Methods' => implode(', ', $this->corsAllowMethods),
                'Access-Control-Allow-Headers' => implode(', ', $this->corsAllowHeaders),
            ];
            return Response::create('', 'html', 204)->header($header);
        }
        return $this->exec();
    }

    public function response($data): Response
    {
        // response
        if ($data instanceof Response) {
            return $data;
        }
        // int, float, string, bool
        else if (is_scalar($data)) {
            return Response::create($data);
        }
        // array
        else if (is_array($data)) {
            return json($data);
        }
        // object
        else if (is_object($data)) {
            if (method_exists($data, 'toArray')) {
                return json($data->toArray());
            } else {
                return Response::create($data);
            }
        }
        throw new Exception('response type not allowed');
    }
}
